package com.inifitness.admin.core.system.service.impl;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.inifitness.admin.core.security.util.SecurityUtils;
import com.inifitness.admin.core.system.converter.ConfigConverter;
import com.inifitness.admin.core.system.mapper.SysConfigMapper;
import com.inifitness.admin.core.system.model.entity.SysConfig;
import com.inifitness.admin.core.system.model.form.ConfigForm;
import com.inifitness.admin.core.system.model.query.ConfigPageQuery;
import com.inifitness.admin.core.system.model.vo.ConfigPageVO;
import com.inifitness.admin.core.system.service.SysConfigService;
import com.inifitness.common.constants.SystemConstants;
import com.inifitness.common.model.Option;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.text.CharSequenceUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;


/**
 * 参数业务实现类
 *
 * @author sunjinfeng
 * @since 2022/6/3
 */
@Service
@RequiredArgsConstructor
public class SysConfigServiceImpl extends ServiceImpl<SysConfigMapper, SysConfig> implements
    SysConfigService {

  private final ConfigConverter configConverter;
  private final CacheManager cacheManager;

  /**
   * 参数分页列表
   *
   * @param queryParams 分页查询参数
   * @return 配置项分页
   */
  @Override
  public Page<ConfigPageVO> getConfigPage(ConfigPageQuery queryParams) {
    // 查询参数
    int pageNum = queryParams.getPageNum();
    int pageSize = queryParams.getPageSize();
    String keywords = queryParams.getKeywords();

    // 查询数据
    Page<SysConfig> configPage = this.page(new Page<>(pageNum, pageSize),
        new LambdaQueryWrapper<SysConfig>()
            .and(CharSequenceUtil.isNotBlank(keywords),
                wrapper ->
                    wrapper.like(CharSequenceUtil.isNotBlank(keywords), SysConfig::getName,
                            keywords)
                        .or()
                        .like(CharSequenceUtil.isNotBlank(keywords), SysConfig::getCode, keywords)
            )
            // 非超级管理员不显示超级管理员参数
            .ne(!SecurityUtils.isRoot(), SysConfig::getCode, SystemConstants.ROOT_ROLE_CODE)
    );

    // 实体转换
    Page<ConfigPageVO> pageResult = configConverter.entity2Page(configPage);
    return pageResult;
  }

  /**
   * 参数下拉列表
   *
   * @return 参数下拉列表
   */
  @Override
  @Cacheable(cacheNames = "listConfigOptions")
  public List<Option<Long>> listConfigOptions() {
    // 查询数据
    List<SysConfig> configList = this.list(new LambdaQueryWrapper<SysConfig>()
        .select(SysConfig::getCode, SysConfig::getValue)
        .orderByAsc(SysConfig::getSort)
    );

    // 实体转换
    return configConverter.entities2Options(configList);
  }

  /**
   * 保存参数
   *
   * @param form 参数表单
   * @return true 保存成功 false 保存失败
   */
  @Override
  @Transactional(rollbackFor = Exception.class)
  @CacheEvict(cacheNames = "listConfigOptions")
  public boolean saveConfig(ConfigForm form) {

    Long configId = form.getId();
    String configCode = form.getCode();

    long count = this.count(new LambdaQueryWrapper<SysConfig>()
        .ne(configId != null, SysConfig::getId, configId)
        .and(wrapper ->
            wrapper.eq(SysConfig::getCode, configCode).or().eq(SysConfig::getName, configCode)
        ));
    Assert.isTrue(count == 0, "参数名称或参数编码重复，请检查！");

    // 实体转换
    SysConfig config = configConverter.form2Entity(form);

    return this.saveOrUpdate(config);
  }

  /**
   * 获取参数表单数据
   *
   * @param configId 参数ID
   * @return {@link ConfigForm} – 参数表单数据
   */
  @Override
  @Cacheable(cacheNames = "getConfigForm", key = "#p0")
  public ConfigForm getConfigForm(Long configId) {
    SysConfig entity = this.getById(configId);
    ConfigForm configForm = configConverter.entity2Form(entity);
    return configForm;
  }

  @Override
  public Object getConfigByCode(String code) {
    SysConfig config = this.getOne(new LambdaQueryWrapper<SysConfig>()
        .select(SysConfig::getCode, SysConfig::getValue, SysConfig::getClazz)
        .eq(SysConfig::getCode, code)
        .last("limit 1"));
    return Convert.convertByClassName(config.getClazz(), config.getValue());
  }

  /**
   * 修改参数状态
   *
   * @param configId 参数ID
   * @param status   参数状态(1:启用；0:禁用)
   * @return {@link Boolean}
   */
  @Override
  @CachePut(cacheNames = "getConfigForm", key = "#p0")
  public boolean updateConfigStatus(Long configId, Integer status) {
    boolean result = this.update(new LambdaUpdateWrapper<SysConfig>()
        .eq(SysConfig::getId, configId)
        .set(SysConfig::getStatus, status));
    return result;
  }

  /**
   * 批量删除参数
   *
   * @param ids 参数ID，多个使用英文逗号(,)分割
   * @return true 删除成功 false 删除失败
   */
  @Override
  @Transactional(rollbackFor = Exception.class)
  @Caching(
      evict = {
          @CacheEvict(cacheNames = "listConfigOptions")
      }
  )
  public boolean deleteConfigs(String ids) {
    List<Long> configIds = Arrays.stream(ids.split(",")).map(Long::parseLong).toList();

    for (Long id : configIds) {
      Optional.ofNullable(cacheManager.getCache("getConfigForm")).map(c -> c.evictIfPresent(id));
    }
    return this.removeByIds(configIds);
  }
}
